package cn.lqz.bucttrain.service.impl;

import cn.lqz.bucttrain.enums.*;
import cn.lqz.bucttrain.exceptions.BaseException;
import cn.lqz.bucttrain.mapper.RouteMapper;
import cn.lqz.bucttrain.mapper.StationMapper;
import cn.lqz.bucttrain.mapper.TrainMapper;
import cn.lqz.bucttrain.pojo.dto.RouteCreateOrUpdateDTO;
import cn.lqz.bucttrain.pojo.dto.RoutePageQueryDTO;
import cn.lqz.bucttrain.pojo.entity.Route;
import cn.lqz.bucttrain.pojo.entity.Station;
import cn.lqz.bucttrain.pojo.entity.Train;
import cn.lqz.bucttrain.pojo.vo.PageResultVO;
import cn.lqz.bucttrain.pojo.vo.RouteVO;
import cn.lqz.bucttrain.service.RouteService;
import cn.lqz.bucttrain.utils.StringUtils;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.InputStream;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

@Service
@Slf4j
public class RouteServiceImpl implements RouteService {
    @Resource
    private RouteMapper routeMapper;
    @Resource
    private StationMapper stationMapper;
    @Resource
    private TrainMapper trainMapper;

    /**
     * 加载或查询路线
     * @param routePageQueryDTO
     * @return
     */
    @Override
    public PageResultVO loadRouteList(RoutePageQueryDTO routePageQueryDTO) {
        log.info("加载或查询路线列表：{}",routePageQueryDTO);
        // 列车类型
        Integer trainType = routePageQueryDTO.getTrainType();
        if (null==trainType){
            routePageQueryDTO.setTrainType(TrainTypeEnum.ALL.getType());
        }
        // 是否中转
        Integer transferChoice = routePageQueryDTO.getTransferChoice();
        if (null==transferChoice){
            routePageQueryDTO.setTransferChoice(TransferChoiceEnum.ALL.getChoice());
        }
        // 查询
        PageHelper.startPage(routePageQueryDTO.getPageNo(),routePageQueryDTO.getPageSize());
        Page<RouteVO> page = routeMapper.findBatch(routePageQueryDTO);
        return new PageResultVO(routePageQueryDTO.getPageNo(),routePageQueryDTO.getPageSize(),page.getTotal(),page.getResult());
    }

    /**
     * 添加或修改路线
     * @param routeCreateOrUpdateDTO
     */
    @Override
    @Transactional
    public void createOrUpdateRoute(RouteCreateOrUpdateDTO routeCreateOrUpdateDTO) {
       log.info("添加或修改路线：{}",routeCreateOrUpdateDTO);
       // 是否中转
        TransferChoiceEnum transferChoiceEnum = TransferChoiceEnum.getByChoice(routeCreateOrUpdateDTO.getTransferChoice());
        // 选择的列车
        Train train = trainMapper.findByTrainId(routeCreateOrUpdateDTO.getTrainId());
        if (null==train || !TrainStatusEnum.ENABLE.getStatus().equals(train.getStatus())){
            throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"列车状态异常");
        }
        // 站点信息
        Station startStation = stationMapper.findByCityAndStationName(routeCreateOrUpdateDTO.getStartStationCity(), routeCreateOrUpdateDTO.getStartStationName());
        Station transferStation = stationMapper.findByCityAndStationName(routeCreateOrUpdateDTO.getTransferStationCity(), routeCreateOrUpdateDTO.getTransferStationName());
        Station endStation = stationMapper.findByCityAndStationName(routeCreateOrUpdateDTO.getEndStationCity(),routeCreateOrUpdateDTO.getEndStationName());
        // 时间
        LocalDateTime startStationStartTime = routeCreateOrUpdateDTO.getStartStationStartTime();
        LocalDateTime transferStationEndTime = routeCreateOrUpdateDTO.getTransferStationEndTime();
        LocalDateTime transferStationStartTime = routeCreateOrUpdateDTO.getTransferStationStartTime();
        LocalDateTime endStationEndTime = routeCreateOrUpdateDTO.getEndStationEndTime();
        int[] stationStatusDisableArray = new int[]{StationStatusEnum.DISABLE.getStatus(),StationStatusEnum.FIX.getStatus()};
        // 站点状态异常
        if (null == startStation || ArrayUtils.contains(stationStatusDisableArray,startStation.getStatus())){
            throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"始发站状态异常");
        }
        if (TransferChoiceEnum.TRANSFER==transferChoiceEnum){
            if (null==transferStation || ArrayUtils.contains(stationStatusDisableArray,transferStation.getStatus())){
                throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"中转站状态异常");
            }
            if (null==transferStationEndTime||null==transferStationStartTime){
                throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"中转时间异常");
            }
            // 发车时间异常
            if (startStationStartTime.isAfter(transferStationEndTime)||transferStationEndTime.isAfter(transferStationStartTime)||transferStationStartTime.isAfter(endStationEndTime)){
                throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"发车时间晚于到达时间");
            }
        }else{
            routeCreateOrUpdateDTO.setTransferStationEndTime(null);
            routeCreateOrUpdateDTO.setTransferStationStartTime(null);
        }
        if (null == endStation || ArrayUtils.contains(stationStatusDisableArray,endStation.getStatus())){
            throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"终点站状态异常");
        }
        // 发车到达时间异常
        if (startStationStartTime.isAfter(endStationEndTime)){
            throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"发车时间晚于到达时间");
        }
        // 放座数量异常
        Integer businessRowStart = routeCreateOrUpdateDTO.getBusinessRowStart();
        Integer businessRowEnd = routeCreateOrUpdateDTO.getBusinessRowEnd();
        Integer commonRowStart = routeCreateOrUpdateDTO.getCommonRowStart();
        Integer commonRowEnd = routeCreateOrUpdateDTO.getCommonRowEnd();
        if (businessRowStart>businessRowEnd || commonRowStart>commonRowEnd || businessRowEnd>commonRowStart){
            throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"放座行数安排异常");
        }
        if ((businessRowEnd-businessRowStart)>train.getBusinessRow()){
            throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"商务座放座行数超过列车商务座数量");
        }
        if((commonRowEnd-commonRowStart)>train.getCommonRow()){
            throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"普通座放座行数超过列车普通座数量");
        }
        if (businessRowEnd>train.getBusinessRow()){
            throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"列车商务座行号为：1 至 "+train.getBusinessRow());
        }
        if (commonRowStart<(train.getBusinessRow()+1)||commonRowEnd>(train.getBusinessRow())+1+train.getCommonRow()){
            throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"列车普通座行号为："+(train.getBusinessRow()+1)+" 至 "+(train.getBusinessRow()+1+train.getCommonRow()));
        }
        if(null==routeCreateOrUpdateDTO.getRouteId()){ // 新增
            // 新增时不能选择已经进入挂停状态的站点
            if (StationStatusEnum.STOP.getStatus().equals(startStation.getStatus())){
                throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"始发站已进入挂停状态");
            }
            if (TransferChoiceEnum.TRANSFER==transferChoiceEnum && StationStatusEnum.STOP.getStatus().equals(transferStation.getStatus())){
                throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"中转站已进入挂停状态");
            }
            if (StationStatusEnum.STOP.getStatus().equals(endStation.getStatus())){
                throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"终点站已进入挂停状态");
            }
            // 必须在列车的空闲时间段安排
            List<Route> clashRouteList = routeMapper.findClashByTrainIdAndStartStationStartTimeAndEndStationEndTime(train.getTrainId(),startStationStartTime,endStationEndTime);
            if (!clashRouteList.isEmpty()){
                throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"存在该列车时间冲突的路线");
            }
            // 更新列车的发车和停车时间
            Train trainForUpdate = new Train();
            trainForUpdate.setTrainId(train.getTrainId());
            if (train.getStartTime()==null){
                trainForUpdate.setStartTime(startStationStartTime);
            }
            if (train.getStopTime()==null){
                trainForUpdate.setStopTime(endStationEndTime);
            }
            trainMapper.update(trainForUpdate);

            Route route = new Route();
            BeanUtils.copyProperties(routeCreateOrUpdateDTO,route);
            route.setStartStationId(startStation.getStationId());
            route.setTransferStationId(TransferChoiceEnum.TRANSFER==transferChoiceEnum?transferStation.getStationId():null);
            route.setEndStationId(endStation.getStationId());
            routeMapper.insert(route);
        }else{ // 修改
            Route route = routeMapper.findByRouteId(routeCreateOrUpdateDTO.getRouteId());
            if (null==route){
                throw new BaseException(ResponseCodeEnum.CODE_600);
            }
            // 若要更换站点，则不能选择已经进入挂停状态的站点
            int stationFixStatus = StationStatusEnum.FIX.getStatus();
            if (!startStation.getStationId().equals(route.getStartStationId()) && startStation.getStatus()==stationFixStatus){
                throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"始发站已进入挂停状态");
            }
            if (TransferChoiceEnum.TRANSFER==transferChoiceEnum && !transferStation.getStationId().equals(route.getTransferStationId()) && transferStation.getStatus()==stationFixStatus){
                throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"中转站已进入挂停状态");
            }
            if (!endStation.getStationId().equals(route.getEndStationId()) && endStation.getStatus()==stationFixStatus){
                throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"终点站已进入挂停状态");
            }
            LocalDateTime now = LocalDateTime.now();
            // 路线是否已在运行中
            boolean isRouteWork = route.getStartStationStartTime().isBefore(now) && route.getEndStationEndTime().isAfter(now);
            // 对于已发车的路线，不能修改trainId和trainNumber
            if (!route.getTrainId().equals(routeCreateOrUpdateDTO.getTrainId()) || !route.getTrainNumber().equals(routeCreateOrUpdateDTO.getTrainNumber())){
                if (isRouteWork){
                    throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"运行中路线不能修改列车信息");
                }
            }
            // 若要修改trainId，则必须选择列车空闲时间段
            List<Route> existClashRouteList = routeMapper.findClashByTrainIdAndStartStationStartTimeAndEndStationEndTimeAndRouteId(train.getTrainId(), startStationStartTime, endStationEndTime, route.getRouteId());
            if (!existClashRouteList.isEmpty()){
                throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"存在该列车时间冲突的路线");
            }
            // 若要修改禁用或维修路线，则必须在路线非运行时间段内
            Integer routeStatus = routeCreateOrUpdateDTO.getStatus();
            if (!route.getStatus().equals(routeStatus) && !RouteStatusEnum.ENABLE.getStatus().equals(routeStatus)){
                if (isRouteWork){
                    throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"路线使用中，无法修改状态");
                }
            }
            Route routeForUpdate = new Route();
            BeanUtils.copyProperties(routeCreateOrUpdateDTO,routeForUpdate);
            routeForUpdate.setStartStationId(startStation.getStationId());
            routeForUpdate.setTransferStationId(TransferChoiceEnum.TRANSFER==transferChoiceEnum?transferStation.getStationId():null);
            routeForUpdate.setEndStationId(endStation.getStationId());
            routeMapper.update(routeForUpdate);
        }
    }

    /**
     * 删除
     * @param routeId
     */
    @Override
    public void deleteRoute(Long routeId) {
        log.info("删除路线：routeId={}",routeId);
        Route route = routeMapper.findByRouteId(routeId);
        if (null==route){
            throw new BaseException(ResponseCodeEnum.CODE_600);
        }
        // 路线必须处于禁用状态才能删除
        if (!RouteStatusEnum.DISABLE.getStatus().equals(route.getStatus())){
            throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"路线必须先处于禁用状态");
        }
        routeMapper.deleteByRouteId(routeId);
    }

    /**
     * 导出路线excel表
     * @param routeVOList
     * @param response
     */
    @Override
    public void exportRouteExcel(List<RouteVO> routeVOList, HttpServletResponse response) {
        log.info("路线：导出excel表");
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("template/路线报表.xlsx");
        try{
            XSSFWorkbook excel = new XSSFWorkbook(inputStream);
            XSSFSheet sheet = excel.getSheet("Sheet1");
            for(int i=1;i<=routeVOList.size();i++){
                XSSFRow xssfRow = sheet.createRow(i);
                for(int j=0;j<21;j++){
                    xssfRow.createCell(j);
                }
            }
            for(int i=0;i<routeVOList.size();i++){
                RouteVO routeVO = routeVOList.get(i);
                XSSFRow row = sheet.getRow(i + 1);
                row.getCell(0).setCellValue(routeVO.getRouteId());
                row.getCell(1).setCellValue(routeVO.getTrainNumber());
                row.getCell(2).setCellValue(routeVO.getTrainId());
                row.getCell(3).setCellValue(TrainTypeEnum.getByType(routeVO.getTrainType()).getDescription());
                row.getCell(4).setCellValue(routeVO.getStartStationCity());
                row.getCell(5).setCellValue(routeVO.getStartStationName());
                String transferStationCity = routeVO.getTransferStationCity();
                String transferStationName = routeVO.getTransferStationName();
                row.getCell(6).setCellValue(StringUtils.isEmpty(transferStationCity)?"":transferStationCity);
                row.getCell(7).setCellValue(StringUtils.isEmpty(transferStationName)?"":transferStationName);
                row.getCell(8).setCellValue(routeVO.getEndStationCity());
                row.getCell(9).setCellValue(routeVO.getEndStationName());
                row.getCell(10).setCellValue(String.valueOf(routeVO.getStartStationStartTime()));
                LocalDateTime transferStationEndTime = routeVO.getTransferStationEndTime();
                LocalDateTime transferStationStartTime = routeVO.getTransferStationStartTime();
                row.getCell(11).setCellValue(transferStationEndTime==null?null:String.valueOf(transferStationEndTime));
                row.getCell(12).setCellValue(transferStationStartTime==null?null:String.valueOf(transferStationStartTime));
                row.getCell(13).setCellValue(String.valueOf(routeVO.getEndStationEndTime()));
                row.getCell(14).setCellValue(routeVO.getBusinessRowStart());
                row.getCell(15).setCellValue(routeVO.getBusinessRowEnd());
                row.getCell(16).setCellValue(routeVO.getCommonRowStart());
                row.getCell(17).setCellValue(routeVO.getCommonRowEnd());
                row.getCell(18).setCellValue(routeVO.getBusinessPrice().setScale(2, BigDecimal.ROUND_HALF_UP).toString());
                row.getCell(19).setCellValue(routeVO.getCommonPrice().setScale(2, BigDecimal.ROUND_HALF_UP).toString());
                row.getCell(20).setCellValue(RouteStatusEnum.getByStatus(routeVO.getStatus()).getDescription());
            }
            ServletOutputStream outputStream = response.getOutputStream();
            excel.write(outputStream);
            excel.close();
            inputStream.close();
        }catch (Exception e){
            log.error("订单导出excel表异常",e);
            throw new BaseException(ResponseCodeEnum.CODE_500);

        }
    }
}
